"""

    JRepackage - This utility is used to batch edit the
                 package structure of a java project.
                 
    Distributed under v2 of the Apache Software License
    A copy of the license can be found here:
    http://www.apache.org/licenses/LICENSE-2.0
    
    Author: Brandon Murphy (officialhopsof@gmail.com)
            Andrew  Scott

"""

import sys
import getopt
import os
import shutil

ADD    = 1
REMOVE = 2


##################################
# Prints the applications command
# line usage message (help)
def usage():
    print("""
    
    JRepackage - This utility is used to batch edit the
                 package structure of a java project.
                 
    Distributed under v2 of the Apache Software License
    A copy of the license can be found here:
    http://www.apache.org/licenses/LICENSE-2.0
    
    Author: Brandon Murphy (officialhopsof@gmail.com)
            Andrew  Scott
    
    -- COMMAND LINE OPTIONS --
    
    -h --help           Prints this help message
    -a --add            Adds the following package
                        to all classes in the specified
                        directory
    -r --remove         Removes the following package
                        from all classes in the specified
                        directory
    -d --directory      Specifies what directory to
                        recursively search for java files
                        from, if not specified, the
                        working directory is used
    -n --noimport       Do not update import statements
    -i --allimport      Changes all import statements to
                        reflect the new package structure
                        regardless as to whether or not
                        they were found in the recursive
                        java file search
    
    
    
    -- ADDITIONAL INFORMATION --
    
    Both the add and remove (-a and -r respectively) flags
    take input in one of two ways. You can specify package
    by package like so:
    
    Given java files with the following package statement:
    package com.foo.bar.mything
    
    ./jrepackage.py -r com.foo.bar -a org.bar.foo
    
    The package statement for those same java files would
    now be:
    package org.bar.foo.mything
    
    or
    
    Given java files with the following package statement:
    package org.bar.foo.mything
    
    ./jrepackage.py -r org -r bar -r foo -a bar -a foo
    
    The package statement for those same java files would
    now be:
    package foo.bar.mything
    
    This application works from the left to right in order
    on all packages listed. The application will
    automatically move the files into their respective
    locations.
    
    Unless you specify the -n [--noimport] flag, imports 
    will also be update to reflect this package structure,
    however, only files found by the recursive search
    will have their import updated, that is, unless
    you specify the -i [--allimport] flag, which will
    update the import statements regardless as to whether
    or not they were for java files found in the
    recursive search.
    """)

##################################
# Takes the file and moves it
# physically from it's old package
# to its new one
def move(javaFile, oldPackage, newPackage):
    oldStructure = oldPackage.split(".")
    newStructure = newPackage.split(".")

    i = 0

    while i               <  len(oldStructure) and
          i               <  len(newStructure) and
          oldStructure[i] == newStructure[i]:

        os.mkri
        i=i+1
        
        

    


##################################
# Adds the package statement to
# all the files in question
# assume package is multiple levels
# e.g. package="org.foo.bar"
def add(fileList, package, noimport, allimport):
    for currentFile in fileList:
        FILE = open(currentFile, "r")
        inComment = False
        done = False
        skip = False
        fileData = FILE.read().split("\n")
        oldPackage = ""
        newPackage = ""
        oldImport = ""
        newImport = ""
        i=0

        while done == False and i < len(fileData):
            line  = fileData[i].strip()

            #adresses being in a comment block first
            if skip == True:
                if line.find("*/") >= 0:
                    skip = False
            #if the line is commented
            else if line.find("//") == 0:
                continue
            #if the line starts a comment thread
            else if line.find("/*") == 0:
				if line.find("*/") < 0:
					skip = True
            #if this line begins with the word "package"    
            else if line.find("package") == 0:
                start = fileData[i].find("package") + len("package") + 1
                end   = fileData[i][start:].find(";") + len("package") + 1
                oldPackage = line[start:end].strip()
                newPackage = oldPackage[0:len(oldPackage)]
                newPackage = package + "." + newPackage  
                fileData[i] = fileData[i].replace(fileData[i][start:end], newPackage)
                if noimport == true:
                    done = True
            #if all imports need changed
            else if allimport == true and line.find("import") == 0:
                start = fileData[i].find("import") + len("import") + 1
                end   = fileData[i][start:].find(";") + len("import") + 1
                oldImport = line[start:end].strip()
                newImport = oldImport[0:len(oldImport)]
                newImport = package + "." + newImport  
                fileData[i] = fileData[i].replace(fileData[i][start:end], newImport)
                
            i=i+1

        FILE.close()
        os.remove(currentFile)
        FILE = open(currentFile + "", "w")
        
        for line in fileData:
            FILE.write(line + "\n")

        FILE.close()

        move(currentFile, oldPackage, newPackage)
        


##################################
# Removes the package statement
# from all the files in question
# assume package is multiple levels
# e.g. package="org.foo.bar"
def remove(fileList, package, noimport, allimport):
    for currentFile in fileList:
        FILE = open(currentFile, "r")
        inComment = False
        done = False
        skip = False
        fileData = FILE.read().split("\n")
        oldPackage = ""
        newPackage = ""
        oldImport = ""
        newImport = ""
        i=0

        while done == False and i < len(fileData):
            line  = fileData[i].strip()

            #adresses being in a comment block first
            if skip == True:
                if line.find("*/") >= 0:
                    skip = False
            #if the line is commented
            else if line.find("//") == 0:
                continue
            #if the line starts a comment thread
            else if line.find("/*") == 0:
				if line.find("*/") < 0:
					skip = True
                skip = True
            #if this line begins with the word "package"
            else if line.find("package") == 0:
                start = fileData[i].find("package") + len("package") + 1
                end   = fileData[i][start:].find(";") + len("package") + 1
                oldPackage = line[start:end].strip()
                packageList = oldPackage.split(".")

                if oldPackage.find(package) == 0:
                    newPackage = oldPackage[len(package)+1:len(oldPackage)]
  
                    fileData[i] = fileData[i].replace(fileData[i][start:end], newPackage)
                    
                if noimport == true:
                    done = True
            #if all imports need adjusted
            else if allimport == true and line.find("import") == 0:
                start = fileData[i].find("import") + len("import") + 1
                end   = fileData[i][start:].find(";") + len("import") + 1
                oldImport = line[start:end].strip()
                packageList = oldImport.split(".")

                if oldImport.find(package) == 0:
                    newImport = oldImport[len(package)+1:len(oldImport)]
  
                    fileData[i] = fileData[i].replace(fileData[i][start:end], newImport)
                
            i=i+1

        FILE.close()
        os.remove(currentFile)
        FILE = open(currentFile + "", "w")
        
        for line in fileData:
            FILE.write(line + "\n")

        FILE.close()

        move(currentFile, oldPackage, newPackage)


##################################
# Returns a list of all java files
# recursively contained in a given
# root directory
def getJavaFilesRecursively(rootDirectory):
    fileList = []
    for root, subFolders, files in os.walk(rootDirectory):
        for currentFile in files:
            extension = os.path.splitext(currentFile)
            if extension[1] == '.java':
                javaFile = os.path.join(root, currentFile)
                fileList.append(javaFile)
            
    return fileList



##################################
# Main Function
def main():
    directory = os.path.abspath(".")
    noimport  = False
    allimport = False
    fileList  = []
    callStack = []

    try:
        opts, args = getopt.getopt(sys.argv[1:], "hnia:r:d:", ["help", "noimport", "allimport", "add=", "remove=", "directory="])        
    except getopt.error, msg:
        print msg
        print "for help use --help"
        sys.exit(2)

    for o, a in opts:
        if o in ("-a", "--add"):
            callStack.append((ADD, a.strip()))
        elif o in ("-r", "--remove"):
            callStack.append((REMOVE, a.strip()))
        elif o in ("-n", "--noimport"):
            if allimport == False:
                noimport = True
            else:
                print("Cannot specify --noimport and --allimport")
                sys.exit(2)
        elif o in ("-i", "--allimport"):
            if noimport == False:
                allimport = True
            else:
                print("Cannot specify --noimport and --allimport")
                sys.exit(2)
        elif o in ("-d", "--directory"):
            directory = os.path.abspath(a)
        elif o in ("-h", "--help"):
            usage()
            sys.exit()

    if len(callStack) > 0:
        fileList = getJavaFilesRecursively(directory)

        for callType, package in callStack:
            if callType == ADD:
                print("Adding package=" + package)
                add(fileList, package, noimport, allimport)
            elif callType == REMOVE:
                print("Removing package=" + package)
                remove(fileList, package, noimport, allimport)

    else:
        print "here"
        usage()
        sys.exit()
    


if __name__ == "__main__":
    main()
